using System;
using System.IO;

namespace OsHelper.DebugTools.LogService
{
	///<summary>
	/// This class stores log messages in a specified file.
	///</summary>
	public class FileService : iService
	{
		private object ob_WriteLock;
		private StreamWriter sw_Writer;
		
		///<summary>
		/// Contains the bitwise combined log levels to write.
		///</summary>
		///<value>
		/// A bitwise combined <see cref="LogLevel" /> specifying the
		/// levels of events to log.
		///</value>
		public LogLevel Level = LogLevel.Standard;
		
		public FileService ()
		{
			this.ob_WriteLock = new object ();
		}
		
		///<summary>
		/// Opens a file to log to.
		///</summary>
		///<param name="path">
		/// <para>A <see cref="String" /> containing the path of the
		/// file to open.</para>
		/// <para>This value is the same as the parameter that would
		/// be passed to <see cref="File.OpenWrite" />.</para>
		///</param>
		///<remarks>
		/// For information on what exceptions are thrown by this
		/// method, see <see cref="FileInfo.OpenWrite" />.
		///</remarks>
		public void Open (string path)
		{
			if (path == null)
				throw new ArgumentNullException ("path");
			
			lock (ob_WriteLock) {
				Close ();
				Stream stream = File.Open (path,
					FileMode.Append, FileAccess.Write,
					FileShare.ReadWrite);
				stream.Seek (0, SeekOrigin.End);
				sw_Writer = new StreamWriter (stream);
			}
		}
		
		///<summary>
		///   Closes the log file and flushes its output.
		///</summary>
		///<remarks>
		///   This method is called automatically when the class is
		///   destroyed.
		///</remarks>
		public void Close ()
		{
			lock (this.ob_WriteLock) {
				if (this.sw_Writer == null)
					return;
				
				try {
					this.sw_Writer.Flush ();
					this.sw_Writer.Close ();
				} catch (System.ObjectDisposedException) {
					// Already done
				}
				this.sw_Writer = null;
			}
		}
		
		public override void Write (LogLevel level, string message)
		{
			if ((this.Level & level) == LogLevel.None)
				return;
			
			if (this.sw_Writer == null)
				return;
			
			lock (ob_WriteLock) {
				string text = string.Format ("[{0:u}, {1}] {2}",
			                             DateTime.Now.ToString(), level, message);
				sw_Writer.WriteLine (text);
				sw_Writer.Flush ();
			}
		}
	}
}

